package cn.ren.cloud.service.impl;

import cn.ren.cloud.constants.VerifyCodeConstant;
import cn.ren.cloud.domain.Login;
import cn.ren.cloud.domain.User;
import cn.ren.cloud.domain.UserAccount;
import cn.ren.cloud.domain.UserBaseInfo;
import cn.ren.cloud.dto.RedisSmsVerifyDto;
import cn.ren.cloud.dto.UserRegisterDto;
import cn.ren.cloud.enums.GlobelExceptionEnum;
import cn.ren.cloud.feign.LoginFeinClient;
import cn.ren.cloud.mapper.UserMapper;
import cn.ren.cloud.result.JsonResult;
import cn.ren.cloud.service.IUserAccountService;
import cn.ren.cloud.service.IUserBaseInfoService;
import cn.ren.cloud.service.IUserService;
import cn.ren.cloud.utils.AssertUtil;
import cn.ren.cloud.utils.BitStatesUtils;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import io.seata.spring.annotation.GlobalTransactional;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

/**
 * <p>
 * 会员登录账号 服务实现类
 * </p>
 *
 * @author Ren
 * @since 2022-12-27
 */
@Service
@Slf4j
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {

    private final RedisTemplate<Object, Object> redisTemplate;
    private final LoginFeinClient loginFeinClient;
    private final IUserAccountService userAccountService;
    private final IUserBaseInfoService userBaseInfoService;


    public UserServiceImpl(RedisTemplate<Object, Object> redisTemplate, LoginFeinClient loginFeinClient, IUserAccountService userAccountService, IUserBaseInfoService userBaseInfoService) {
        this.redisTemplate = redisTemplate;
        this.loginFeinClient = loginFeinClient;
        this.userAccountService = userAccountService;
        this.userBaseInfoService = userBaseInfoService;
    }

    /**
     * 用户注册
     *
     * @param userRegisterDto 接收前端的数值
     */
    @Override
    @GlobalTransactional(rollbackFor = Exception.class)
    public void register(UserRegisterDto userRegisterDto) {
        // 获取前端传值,电话，密码，图形验证码，短信验证码，注册途径
        String mobile = userRegisterDto.getMobile();
        String password = userRegisterDto.getPassword();
        String imageCode = userRegisterDto.getImageCode();
        String smsCode = userRegisterDto.getSmsCode();
        Integer regChannel = userRegisterDto.getRegChannel();
        // 效验图形验证码
        String smsCodeKey = VerifyCodeConstant.REDIS_PICTURE_CODE + userRegisterDto.getImageCodeKey();
        Object sms = redisTemplate.opsForValue().get(smsCodeKey);
        // 效验图形验证码是否过期
        AssertUtil.isNotNull(sms, GlobelExceptionEnum.USER_SMS_CODE_NULL);
        // 效验图形验证码是否正确
        RedisSmsVerifyDto redisSmsVerifyCodeDto = (RedisSmsVerifyDto) sms;
        String redisSmsCode = redisSmsVerifyCodeDto.getCode();
        AssertUtil.isEqualsIgnoreCase(imageCode, redisSmsCode, GlobelExceptionEnum.USER_REDIS_CODE_ERROR);
        // 效验手机验证码
        String phoneCodeKey = VerifyCodeConstant.REDIS_REGISTER_PHONE + mobile;
        Object o = redisTemplate.opsForValue().get(phoneCodeKey);
        // 效验手机验证码是否为空
        AssertUtil.isNotNull(o, GlobelExceptionEnum.USER_PHONE_CODE_NULL);
        // 效验手机验证是否正确
        RedisSmsVerifyDto redisSmsVerifyDto = (RedisSmsVerifyDto) o;
        String code = redisSmsVerifyDto.getCode();
        AssertUtil.isEqualsIgnoreCase(smsCode, code, GlobelExceptionEnum.USER_PHONE_CODE_ERROR);
        // 效验手机号是否存在
        selectByPhone(mobile);
        // 保存login
        Long loginId = saveLogin(mobile, password);
        // 保存user
        Long userId = saveUser(mobile, loginId);
        // 初始化用户初始信息
        saveUserAccount(userId);
        // 初始化用户基本信息
        saveUserBaseInfo(regChannel, userId);
    }

    /**
     * 用户数据添加
     *
     * @param mobile 手机号
     * @param loginId 日志ID
     * @return 用户ID
     */
    private Long saveUser(String mobile, Long loginId) {
        // 新建一个User接收参数
        User user = new User();
        // 添加User数据
        user.setCreateTime(System.currentTimeMillis());
        long bitState = BitStatesUtils.addState(BitStatesUtils.OP_REGISTED, BitStatesUtils.OP_ACTIVED);
        bitState =  BitStatesUtils.addState(bitState, BitStatesUtils.OP_AUTHED_PHONE);
        user.setBitState(bitState);
        user.setPhone(mobile);
        user.setLoginId(loginId);
        user.setNickName(mobile);
        // 使用父类方法提交数据
        insert(user);
        // 返回一个UserID
        return user.getId();
    }

    /**
     * 用户信息初始化
     *
     * @param regChannel 注册方式
     * @param userId 用户ID
     */
    private void saveUserBaseInfo(Integer regChannel, Long userId) {
        // 新建一个userBaseInfo
        UserBaseInfo userBaseInfo = new UserBaseInfo();
        // 添加数据
        userBaseInfo.setCreateTime(System.currentTimeMillis());
        userBaseInfo.setId(userId);
        userBaseInfo.setRegChannel(regChannel);
        // 使用userBaseInfoService调用方法
        userBaseInfoService.insert(userBaseInfo);
    }

    /**
     * 用户账号初始化
     *
     * @param userId 用户ID
     */
    private void saveUserAccount(Long userId) {
        // 新建一个userAccount
        UserAccount userAccount = new UserAccount();
        // 添加userAccount数据
        userAccount.setCreateTime(System.currentTimeMillis());
        userAccount.setId(userId);
        userAccount.setUpdateTime(System.currentTimeMillis());
        // 使用userAccountService调用方法
        userAccountService.insert(userAccount);
    }

    /**
     * 添加用户登录信息
     *
     * @param mobile 用户账号
     * @param password 用户密码
     * @return date时间
     */
    private Long saveLogin(String mobile, String password) {
        // 新建一个login
        Login login = new Login();
        // 添加数据
        login.setPassword(password);
        login.setUsername(mobile);
        login.setType(Login.RECEPTION_TYPE);
        login.setEnabled(Login.INITIAL_STATE_OPEN);
        login.setAccountNonExpired(Login.INITIAL_STATE_OPEN);
        login.setCredentialsNonExpired(Login.INITIAL_STATE_OPEN);
        login.setAccountNonLocked(Login.INITIAL_STATE_OPEN);
        // 调用loginFeinClient接口
        JsonResult jsonResult = loginFeinClient.saveOrUpdate(login);
        // 断言，判断他成功，否则抛出异常
        AssertUtil.isTrue(jsonResult.isSuccess(), GlobelExceptionEnum.GLOBE_EXCEPTION_ENUM_PARAM_ERROR);
        Object data = jsonResult.getData();
        // 断言，判断不为空，否则抛出异常
        AssertUtil.isNotNull(data, GlobelExceptionEnum.GLOBE_EXCEPTION_ENUM_PARAM_ERROR);
        return Long.valueOf(data.toString());
    }

    /**
     * 判断用户手机号是否存在
     *
     * @param mobile 用户手机号
     */
    private void selectByPhone(String mobile) {
        // 新建EntityWrapper
        EntityWrapper<User> wrapper = new EntityWrapper<>();
        // 与数据库做比较
        wrapper.eq("phone", mobile);
        // 调用selectOne方法
        User user = selectOne(wrapper);
        // 断言，判断手机号为空，否则抛出异常
        AssertUtil.isNull(user, GlobelExceptionEnum.USER_PHONE_EXISTENCE);
    }
}
